Spring Boot + Activiti 完美结合,快速实现工作流 您所在的位置:网站首页 SpringBoot + Activiti 完美结合快速实现工作流 Spring Boot + Activiti 完美结合,快速实现工作流

Spring Boot + Activiti 完美结合,快速实现工作流

2024-05-20 04:09| 来源: 网络整理| 查看: 265

关于工作流之前分享过一篇flowable,今天分享一下另外一个实现:Activiti

flowable的工作流实现可以看之前的文章:Spring Boot + flowable 完美结合,快速实现工作流

1、概念

工作流。通过计算机对业务流程自动化执行管理,主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

2、Activiti7

介绍

Activiti是一个工作流引擎,Activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由Activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

在使用activiti之前,首先需要编写activiti.cfg.xml配置文件。

activiti.cfg.xml

activiti的引擎配置文件,包括:ProcessEngineConfiguration的定义、数据源定义、事务管理器等。其实就是一个Spring配置文件。

代码语言:javascript复制

Activiti流程框架,在前期主要需要了解的就是数据库表的创建、流程的部署、流程的启动和各个阶段任务的完成。

3、流程引擎配置类

流程引擎配置类(ProcessEngineConfiguration),通过 ProcessEngineConfiguration 可以创建工作流引擎 ProceccEngine。

4、工作流引擎的创建

工作流引擎的创建主要有两种方式:默认创建方式和一般创建方式

默认创建方式

代码语言:javascript复制ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); System.out.println(processEngine);

一般创建方式

代码语言:javascript复制//使用自定义方式创建 ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml"); //获取流程引擎对象:通过 ProcessEngineConfiguration 创建 ProcessEngine,此时会创建数据库 ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

当创建好工作流引擎后,对应的数据库中会自动生成25张数据库表。

ACT_GE_PROPERTY中会先展示下一次流程的ID(next.dbid),并且在下一次流程部署的时候,对下一次流程的ID进行赋值。

5、Activiti表说明

这里以表名的前缀进行说明:

6、Service服务接口

Activiti中还有许多的Service服务接口。这些Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,我们可以使用这些接口操作服务对应的数据表。

Service创建方式

通过ProcessEngine创建Service方式:

代码语言:javascript复制Runtimeservice runtimeService = processEngine.getRuntimeService(); RepositoryService repositoryService = processEngine.getRepositoryService(); TaskService taskService = processEngine.getTaskService();

Service总览

RepositoryService

Activiti 的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此service将流程定义文件的内容部署到计算机。除了部署流程定义以外,还可以查询引擎中的发布包和流程定义。

暂停或激活发布包,对应全部和特定流程定义。暂停意味着它们不能再执行任何操作了,激活是对应的反向操作。获得多种资源,像是包含在发布包里的文件,或引擎自动生成的流程图。获得流程定义的pojo版本,可以用来通过java解析流程,而不必通过xml。

Runtimeservice

Activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息

Taskservice

Activiti的任务管理类。可以从这个类中获取任务的信息。

Historyservice

Activiti的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比如流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径,等等。这个服务主要通过查询功能来获得这些数据。

ManagementService

Activiti的引擎管理类,提供了对Activiti流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti 系统的日常维护。

7、流程图符号说明

BPMN插件

使用IDEA进行开发,建议下载一个插件。actiBPM插件,直接搜索下载。

流程符号、画流程图

流程符号:事件Event,活动Activity,网关Gateway,流向

使用流程设计器画出流程图

创建bpmn文件,在流程设计器使用流程符号来表达流程,指定流程的key,指定任务负责人生成png文件创建的bpmn文件要放在resourse下的bpmn文件夹下。

注意:当前任务流程的ID不能是数字开头。

8、流程的操作

部署流程

使用 Activiti 提供的 API 把流程图的内容写入到数据库中

属于资源操作类,使用 RepositoryService

单文件部署:把bpmn文件和png文件逐个处理压缩包部署:把bpmn文件和png文件打成压缩包来处理部署操作表:act_re_deployment、act_re_procdef、act_ge_bytearray代码语言:javascript复制/ * 流程部署 */ public void deployment() { // 创建 ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取 RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 使用 service 进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据中 Deployment deployment = repositoryService.createDeployment() .name("出差申请流程") //流程图标的名字 .addClasspathResource("bpmn/evection.bpmn") //bpmn文件 .addClasspathResource("bpmn/evection.png") //bpmn文件生成的 .deploy(); // 输出部署信息 System.out.println("流程部署ID:" + deployment.getId()); System.out.println("流程部署名字:" + deployment.getName()); }

有时候我们会有多个流程,需要创建多个bpmn流程文件,这个时候想要同时部署,我们可以对bpmn文件进行打包压缩,使用Zip包进行批量的部署

代码语言:javascript复制/ * 使用Zip包进行批量的部署 */ @Test public void deployProcessByZip() { // 获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取 RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 流程部署 // 读取资源包文件,构造成 InputStream InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip"); // 使用 InputStream 构造 ZipInputStream ZipInputStream zipInputStream = new ZipInputStream(inputStream); // 使用压缩包的流,进行流程的部署 Deployment deploy = repositoryService.createDeployment() .addZipInputStream(zipInputStream) .deploy(); // 输出 System.out.println("流程部署的ID:" + deploy.getId()); System.out.println("流程部署的名称:" + deploy.getName()); }

操作的数据库表:

act_ge_bytearrayact_ge_propertyact_re_deploymentact_re_procdef

启动流程实例

流程部署完成以后,需要启动流程实例。使用 RuntimeService 根据流程定义的 key进行启动。

核心代码:

代码语言:javascript复制/ * 启动流程 */ public void starProcess() { // 创建 ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取 RunTimeService RuntimeService runtimeService = processEngine.getRuntimeService(); // 根据流程定义的ID启动流程 ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection"); // 输出内容 System.out.println("流程定义ID:" + instance.getProcessDefinitionId()); System.out.println("流程实例的ID:" + instance.getId()); System.out.println("当前活动的ID:" + instance.getActivityId()); }

任务查询

使用 TaskService ,根据流程定义的 key ,任务负责人来进行查询

核心代码:

代码语言:javascript复制/ * 查询个人待执行的任务 */ @Test public void findPersonalTaskList() { // 获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取TaskService TaskService taskService = processEngine.getTaskService(); // 根据流程的key和任务的负责人去查询任务 List taskList = taskService.createTaskQuery() .processDefinitionKey("myEvection") // 流程的key .includeProcessVariables() .taskAssignee("zhangsan") // 要查询的负责人 .list(); // 输出 for (Task task : taskList) { System.out.println("流程实例的ID:" + task.getProcessInstanceId()); System.out.println("任务的ID:" + task.getId()); System.out.println("任务的负责人:" + task.getAssignee()); System.out.println("任务的名称:" + task.getName()); } }

任务完成

使用 TaskService ,用任务 ID 直接完成任务。

核心代码:

代码语言:javascript复制/ * 完成个人任务 */ @Test public void completTask() { String key = "testCandidiate"; String assignee = "张三1"; //任务的负责人 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .processDefinitionKey(key) .taskAssignee(assignee) .singleResult(); if (task != null) { taskService.complete(task.getId()); } }

关于流程实例的挂起和激活

全部流程实例的挂起和激活

代码语言:javascript复制/ * 全部流程实例的挂起和激活 */ @Test public void suspendAllProcessInstance() { // 1.获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2.获取 RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 3.查询流程定义 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("myEvection") .singleResult(); // 4.获取当前流程定义的实例是否都是挂起状态 boolean flag = processDefinition.isSuspended(); // 5.获取流程定义的ID String id = processDefinition.getId(); // 6.判断是否挂起状态。是:改为激活;否:改为挂起 if (flag) { // 改为激活. 参数1:流程定义的ID,参数2:是否激活,参数3:激活时间 repositoryService.activateProcessDefinitionById(id, true, null); System.out.println("流程定义ID:" + id + "已激活"); } else { // 改为挂起. 参数1:流程定义的ID;参数2:是否挂起;参数3:挂起时间 repositoryService.suspendProcessDefinitionById(id, true, null); System.out.println("流程定义ID:" + id + "已挂起"); } }

单个流程实例的挂起和激活

代码语言:javascript复制/ * 单个流程实例的挂起和激活 */ @Test public void suspendSingleProcessInstance() { // 1.获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2.获取 RuntimeService RuntimeService runtimeService = processEngine.getRuntimeService(); // 3.通过 RuntimeService 获取流程实例对象 ProcessInstance instance = runtimeService.createProcessInstanceQuery() .processInstanceId("17501") .singleResult(); // 4.得到当前流程实例的暂停状态 boolean flag = instance.isSuspended(); // 5.获取流程实例的ID String instanceId = instance.getId(); // 6.判断是否暂停。是:改为激活;否:改为暂停 if (flag) { runtimeService.activateProcessInstanceById(instanceId); System.out.println("流程实例ID:" + instanceId + "已激活"); } else { runtimeService.suspendProcessInstanceById(instanceId); System.out.println("流程实例ID:" + instanceId + "已暂停"); } }

注意:流程实例在挂起的状态下是无法进行下一步操作的。

9、流程变量

我们在使用流程变量的时候。如果我们将一个对象存储到一个流程变量中,那么这个对象需要实现Serializable接口。

代码语言:javascript复制/ * 出差申请中的流程变量对象 */ @NoArgsConstructor @AllArgsConstructor @Data public class Evection implements Serializable { private Long id; //主键ID private Integer days; //出差天数 private String evectionName; //出差单名字 private Date startTime; //出差开始时间 private Date endTime; //出差结束时间 private String address; //目的地 private String reason; //出差原因 }

流程变量的作用域

整个流程实例、任务、执行实例。默认:整个流程实例。

使用方法

在属性上使用UEL表达式 ${assignee},assignee就是一个流程变量的名称。

在连线上使用UEL表达式 ${days

Activiti和SpringBoot的整合开发

配置文件:

代码语言:javascript复制spring: application: name: actspringboot datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/actspring?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=UTC username: root password: root activiti: # false:默认值。activiti在启动时,会对比数据库表中保存的版本。如果没有表或者版本不匹配,将抛出异常 # true:activiti会对数据库中所有表进行更新操作,如果表不存在,则会自动创建 # create_drop:在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表) # drop-create:在activiti启动时删除原来的旧表,然后再创建新表(不需要手动关闭引擎) # 线上一般使用false,开发中使用true database-schema-update: true # 自动部署验证设置:true-开启(默认)、false-关闭 check-process-definitions: false # 开启历史表 db-history-used: true # 历史记录存储等级 history-level: full server: port: 8082

PS:防止找不到本篇文章,可以收藏点赞,方便翻阅查找哦。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有